package org.apache.dolphinscheduler.api.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.UserAuthenticationService;
import org.apache.dolphinscheduler.api.utils.DateUtil;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.enums.UserType;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.entity.UserAuthentication;
import org.apache.dolphinscheduler.dao.mapper.UserAuthenticationMapper;
import org.apache.dolphinscheduler.dao.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class UserAuthenticationServiceImpl extends ServiceImpl<UserAuthenticationMapper, UserAuthentication> implements UserAuthenticationService {
	
	@Value("${file.upload}")
	private String uploadPath;
	
	@Autowired
    private UserMapper userMapper;
	
	public UserAuthentication getUserAuthById(Integer id) {
		return getById(id);
	}

	public List<UserAuthentication> queryAuthByUserId(Integer userId) {
		QueryWrapper<UserAuthentication> qw = new QueryWrapper<UserAuthentication>();
		qw.eq("user_id", userId);
		qw.orderByDesc("create_time");
		return list(qw);
	}
	
	public Result<Object> addUserAuth(User loginUser, UserAuthentication userAuth) {
		Result<Object> result = new Result<>();
		// 判断是否为重复提交
		// 判断用户是否为个人升级至企业
		userAuth.setCreateTime(new Date());
		userAuth.setUserId(loginUser.getId());
		userAuth.setAuthStatus(3);
		saveOrUpdate(userAuth);
		User user = userMapper.selectById(loginUser.getId());
		if(user != null) {
			if(user.getAuditStatus() != null) {
				if(userAuth.getQualificationType() == 1) {
					user.setAuditStatus(3);
				} else if (userAuth.getQualificationType() == 2) {
					user.setEnterpriseAuditStatus(3);
				}
				userMapper.updateById(user);
			}
		}
		result.setData(userAuth);
		result.setCode(Status.SUCCESS.getCode());
    	result.setMsg(Status.SUCCESS.getMsg());
    	return result;
	}
	
	public Result<Object> auditUserAuth(User loginUser, Integer userId, Integer authStatus, String remark) {
		Result<Object> result = new Result<>();
		if (loginUser.getRoleId() != null && loginUser.getRoleId().intValue() != 1) {
            result.setCode(Status.USER_NO_OPERATION_PERM.getCode());
        	result.setMsg(Status.USER_NO_OPERATION_PERM.getMsg());
            return result;
        }
		User user = userMapper.selectById(userId);
		UserAuthentication ua = getUserAuthentication(userId, 3);
		if(ua != null) {
			if(ua.getAuthStatus() == authStatus) {
				result.setCode(Status.AUDIT_USER_CONSISTENT.getCode());
	        	result.setMsg(Status.AUDIT_USER_CONSISTENT.getMsg());
	            return result;
			}
			ua.setAuditTime(new Date());
			ua.setAuthStatus(authStatus);
			ua.setRemark(remark);
			updateById(ua);
			if(user != null) {
				if(ua.getQualificationType() == 1) {
					user.setAuditStatus(authStatus);
				}
				if(ua.getQualificationType() == 2) {
					user.setEnterpriseAuditStatus(authStatus);
				}
				userMapper.updateById(user);
			}
			result.setCode(Status.SUCCESS.getCode());
	    	result.setMsg(Status.SUCCESS.getMsg());
	    	return result;
		} else {
			result.setCode(Status.AUDIT_USER_NOT_SUBMIT.getCode());
        	result.setMsg(Status.AUDIT_USER_NOT_SUBMIT.getMsg());
            return result;
		}
	}
	
	public UserAuthentication getUserAuthentication(Integer userId, Integer authStatus) {
		QueryWrapper<UserAuthentication> qw = new QueryWrapper<UserAuthentication>();
		qw.eq("user_id", userId);
		qw.eq("auth_status", authStatus);
		qw.last("LIMIT 1");
		qw.orderByDesc("create_time");
		return getOne(qw);
	}
	
	public UserAuthentication getUserAuthenticationByStatus(Integer userId, Integer authStatus, Integer enterpriseAuditStatus) {
		QueryWrapper<UserAuthentication> qw = new QueryWrapper<UserAuthentication>();
		qw.eq("user_id", userId);
		qw.and(warrper -> warrper.eq("auth_status", authStatus).or().eq("auth_status", enterpriseAuditStatus));
		qw.last("LIMIT 1");
		qw.orderByDesc("create_time");
		return getOne(qw);
	}
	
	public Result<Object> uploadFile(User loginUser, MultipartFile multipartFile) {
		Result<Object> result = new Result<>();
		
		String filePath = "/" + DateUtil.getNowYYYYMMDD().substring(0, 6) + "/";
        File file = new File(uploadPath + filePath);
        log.info("filePath:" + (uploadPath + filePath));
        if (!file.exists()) {
            file.mkdirs();
        }
        String name = FilenameUtils.getBaseName(multipartFile.getOriginalFilename()) + DateUtil.getNowYYYYMMDDHHmmss();
    	String hz = FilenameUtils.getExtension(multipartFile.getOriginalFilename());
    	String fileName = name + "." + hz;
        if (fileName.length() > 255) {
            fileName = fileName.substring(fileName.length() - 255);
        }
        
        String destName = uploadPath + filePath + fileName;
        log.info("destName:" + destName);
        if (isSpecialChar(multipartFile.getOriginalFilename())) {
            log.error("uploadFile.SpecialChar.fileName:" + multipartFile.getOriginalFilename());
            result.setCode(Status.UPLOAD_FILE_SPECIALCHAR.getCode());
        	result.setMsg(Status.UPLOAD_FILE_SPECIALCHAR.getMsg());
            return result;
        }
        try {
        	FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), new File(destName));
//        	multipartFile.transferTo(new File(destName).getAbsoluteFile());
	    } catch (Exception e) {
	        log.error("上传文件失败:", e);
	        try {
	            File d = new File(destName);
	            if (d.exists()) {
	                d.delete();
	            }
	        } catch (Exception ee) {
	            log.error("file upload error and delete error:" + e.getMessage());
	        }
	    }
        result.setData(filePath + fileName);
		result.setCode(Status.SUCCESS.getCode());
    	result.setMsg(Status.SUCCESS.getMsg());
    	return result;
	}
	
	public Result<Object> getFile(HttpServletResponse resp, String fileName) {
		Result<Object> result = new Result<>();
		if(StringUtils.isBlank(fileName)){
			result.setCode(Status.FILE_PATH_NOT_EXIST.getCode());
			result.setMsg(Status.FILE_PATH_NOT_EXIST.getMsg());
			return result;
		}

		String fileLocal = uploadPath + fileName;
		log.info("filePath:" + fileLocal);
		if(fileLocal.contains("..")) {
			result.setCode(Status.FILE_PATH_ERROR.getCode());
        	result.setMsg(Status.FILE_PATH_ERROR.getMsg());
            return result;
        }
		File file = new File(fileLocal);
        if (!file.exists()) {
        	result.setCode(Status.FILE_PATH_NOT_EXIST.getCode());
        	result.setMsg(Status.FILE_PATH_NOT_EXIST.getMsg());
            return result;
        }
        OutputStream os = null;
        try {
            os = resp.getOutputStream();
            resp.setHeader("Content-Disposition", "filename=" + fileName);
            resp.setContentType("image/jpeg;charset=UTF-8");
            write(fileLocal, os);
            log.info("getFile.end.fileName:" + fileName);
        } catch (Exception e) {
            log.error("dealFile error:" + fileName, e);
            return null;
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    log.error("dealFile.error", e);
                }
            }
        }
		return null;
	}
	
	public boolean isSpecialChar(String str) {
        String regEx = "[`~!@#$%^&*()+=|{}':;'\\[\\]<>/?~！@#￥%……&*——+|{}【】‘；：”“’。，、？]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        return m.find();
    }
	
	public void write(String filename, OutputStream os) throws IOException {
        File f = new File(filename);
        if (!f.exists()) {
            throw new FileNotFoundException(filename);
        }
        long max = 314572800L;//1024*1024*300;
        FileChannel channel = null;
        FileInputStream fs = null;
        try {
            fs = new FileInputStream(f);
            channel = fs.getChannel();
            ByteBuffer byteBuffer = ByteBuffer.allocate(f.length() > max ? (int) max : (int) f.length());
            while ((channel.read(byteBuffer)) > 0) {
                os.write(byteBuffer.array());
                os.flush();
                byteBuffer.clear();
            }
            return;
        } catch (IOException e) {
            log.error("write.error", e);
            throw e;
        } finally {
            try {
                channel.close();
            } catch (IOException e) {
                log.error("write.error", e);
            }
            try {
                fs.close();
            } catch (IOException e) {
                log.error("write.error", e);
            }
        }
    }
}
